package com.lw.service.impl;

import com.lw.common.utils.StrUtils;
import com.lw.common.vo.*;
import com.lw.entity.TbLog;
import com.lw.mapper.TbLogMapper;
import com.lw.service.TbLogService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.lw.entity.table.TbLogTableDef.TB_LOG;
import static com.lw.entity.table.TbUserTableDef.TB_USER;

/**
 * 系统日志表 服务层实现。
 *
 * @author lw
 * @since 2025年05月14日 00:26:38
 */
@Service
public class TbLogServiceImpl extends ServiceImpl<TbLogMapper, TbLog> implements TbLogService {

    @Resource
    private TbLogMapper tbLogMapper;

    @Override
    public VisitStatsVO getVisitStats() {
        VisitStatsVO result = new VisitStatsVO();
        // 访客数统计(UV)
        VisitStatsBO uvStats = this.tbLogMapper.getUvStats();
        if (uvStats != null) {
            result.setTodayUvCount(uvStats.getTodayCount());
            result.setTotalUvCount(uvStats.getTotalCount());
            result.setUvGrowthRate(uvStats.getGrowthRate());
        }
        // 浏览量统计(PV)
        VisitStatsBO pvStats = this.tbLogMapper.getPvStats();
        if (pvStats != null) {
            result.setTodayPvCount(pvStats.getTodayCount());
            result.setTotalPvCount(pvStats.getTotalCount());
            result.setPvGrowthRate(pvStats.getGrowthRate());
        }

        return result;
    }

    @Override
    public VisitTrendVO getVisitTrend(LocalDate startDate, LocalDate endDate) {
        VisitTrendVO visitTrend = new VisitTrendVO();
        List<String> dates = new ArrayList<>();

        // 获取日期范围内的日期
        while (!startDate.isAfter(endDate)) {
            dates.add(startDate.toString());
            startDate = startDate.plusDays(1);
        }
        visitTrend.setDates(dates);

        // 获取访问量和访问 IP 数的统计数据
        List<VisitCount> pvCounts = tbLogMapper.getPvCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59");
        List<VisitCount> ipCounts = tbLogMapper.getIpCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59");

        // 将统计数据转换为 Map
        Map<String, Integer> pvMap = pvCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount));
        Map<String, Integer> ipMap = ipCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount));

        // 匹配日期和访问量/访问 IP 数
        List<Integer> pvList = new ArrayList<>();
        List<Integer> ipList = new ArrayList<>();

        for (String date : dates) {
            pvList.add(pvMap.getOrDefault(date, 0));
            ipList.add(ipMap.getOrDefault(date, 0));
        }

        visitTrend.setPvList(pvList);
        visitTrend.setIpList(ipList);

        return visitTrend;
    }

    @Override
    public Page<TbLog> getLogPage(LogVo logVo) {
        Page<TbLog> page = new Page<>();
        page.setPageNumber(logVo.getPageNum());
        page.setPageSize(logVo.getPageSize());

        QueryChain<TbLog> operator = queryChain().select(TB_LOG.ALL_COLUMNS, TB_USER.NICKNAME.as("operator")).from(TB_LOG)
                .leftJoin(TB_USER).on(TB_USER.ID.eq(TB_LOG.CREATE_BY)).orderBy(TB_LOG.CREATE_TIME.desc());
        if (StrUtils.hasLength(logVo.getKeywords())) {
            operator.where(TB_LOG.CONTENT.like("%" + logVo.getKeywords() + "%")
                    .or(TB_LOG.IP.like("%" + logVo.getKeywords() + "%"))
                    .or(TB_USER.NICKNAME.like("%" + logVo.getKeywords() + "%"))
                    .or(TB_USER.NICKNAME.like("%" + logVo.getKeywords() + "%")));
        }
        List<String> createTime = logVo.getCreateTime();
        if (StrUtils.hasLength(createTime.get(0)) && StrUtils.hasLength(createTime.get(1))) {
            operator.and(TB_LOG.CREATE_TIME.between(createTime.get(0), createTime.get(1)));
        }
        return operator.pageAs(page, TbLog.class);
    }
}
